package lsp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicBoolean;

public class InPackageHandler implements Runnable {
	private DatagramSocket ds;
	private LinkedBlockingDeque<LspMessage> entrada;
	private LinkedBlockingDeque<LspMessage> saida;
	// private AtomicBoolean epochExpired;
	private AtomicBoolean epochLimitExpired;
	private InetAddress servidor;
	//private short connId;

	public InPackageHandler(DatagramSocket ds,
			LinkedBlockingDeque<LspMessage> entrada,
			LinkedBlockingDeque<LspMessage> saida,
			AtomicBoolean epochLimitExpired, InetAddress servidor) {
		this.ds = ds;
		this.entrada = entrada;
		this.saida = saida;
		this.epochLimitExpired = epochLimitExpired;
		this.servidor = servidor;
		//this.connId = connId;
	}

	@Override
	public void run() {
		byte[] pacoteRecebido;
		DatagramPacket pacote;
		LspMessage mensagemRecebida;
		try {
			while (!Thread.currentThread().isInterrupted()) {
				// if (this.epochExpired.get())
				// epochExpiredRotine();
				pacoteRecebido = new byte[1000];
				pacote = new DatagramPacket(pacoteRecebido,
						pacoteRecebido.length);
				ds.receive(pacote);
				mensagemRecebida = new LspMessage(pacote.getData());
				if (pacote.getAddress().getHostAddress()
						.equals(this.servidor.getHostAddress()) // Verifica IP
																// do servidor
						/*&& mensagemRecebida.getConnId() == this.connId*/) {
					if (mensagemRecebida.getMsgType() == 1) // Dados
						recebeData(mensagemRecebida);
					else if (mensagemRecebida.getMsgType() == 2) // Ack
						recebeAck(mensagemRecebida);
					this.epochLimitExpired.set(false); // Reinicia o contador
				}
			}
		} catch (IOException | InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
	}

	// private void epochExpiredRotine() {
	// TODO Auto-generated method stub

	// }

	private void recebeAck(LspMessage mensagemRecebida)
			throws InterruptedException {
		if (!this.saida.isEmpty()
				&& mensagemRecebida.getSeqNumber() == this.saida.peekLast()
						.getSeqNumber())
			this.saida.takeLast();
		if (mensagemRecebida.getSeqNumber() == 0) // Resposta do Connect
			this.entrada.putFirst(mensagemRecebida);
	}

	private void recebeData(LspMessage mensagemRecebida)
			throws InterruptedException {
		if (this.entrada.isEmpty() || (mensagemRecebida.getSeqNumber() == (this.entrada.peekFirst()
				.getSeqNumber() + 1))) {
			this.entrada.putFirst(mensagemRecebida);
			this.saida.putLast(new LspMessage((short) 2, mensagemRecebida.getConnId(),
					mensagemRecebida.getSeqNumber(), "".getBytes())); // Adiciona
																		// o ACK
																		// na
																		// pilha
																		// de
																		// saida
		}
	}

}
